<script setup lang="ts">
import { onMounted, ref, computed } from 'vue';
import G6 from '@antv/g6';
import * as KgTipsComponent from './components/KgTips.vue';
import * as KgLegendComponent from './components/KgLegend.vue';
import * as KgNodeDetailComponent from './components/KgNodeDetail.vue';
import { useGraphStore } from '@/store/kg/graph';
import { Refresh } from '@element-plus/icons-vue';

// 使用pinia store
const graphStore = useGraphStore();

const container = ref<HTMLElement | null>(null);
const drawerVisible = ref(false);
const isNewNode = ref(false);

// 从store获取相关状态
const nodeTypes = computed(() => graphStore.nodeTypes);
const selectedType = computed({
  get: () => graphStore.searchForm.selectedType,
  set: val => {
    graphStore.searchForm.selectedType = val;
  },
});
const searchKeyword = computed({
  get: () => graphStore.searchForm.searchKeyword,
  set: val => {
    graphStore.searchForm.searchKeyword = val;
  },
});
const nodeProperties = computed(() => graphStore.nodeProperties);
const loading = computed(() => graphStore.loading);

// 使用组件正确的导入方式
const KgTips = KgTipsComponent.default || KgTipsComponent;
const KgLegend = KgLegendComponent.default || KgLegendComponent;
const KgNodeDetail = KgNodeDetailComponent.default || KgNodeDetailComponent;

// 根据节点类型应用样式
const applyNodeStyle = (nodes) => {
  return nodes.map(node => {
    // 根据节点类型设置不同的颜色和大小
    let size = 40;
    let color = '#5B8FF9';

    // 设置大小：课程和案例较大，组件和知识点较小
    if (node.type === 'Course') {
      size = 50;
      color = '#FF6B3B'; // 橙色
    } else if (node.type === 'Case') {
      size = 46;
      color = '#d1db12'; // 黄色
    } else if (node.type === 'Component') {
      size = 42;
      color = '#9661BC'; // 紫色
    } else if (node.type === 'Knowledge') {
      size = 42;
      color = '#60C0DD'; // 蓝色
    }

    return {
      ...node,
      size,
      style: {
        ...node.style,
        fill: color
      }
    };
  });
};

// 根据边类型应用样式
const applyEdgeStyle = (edges) => {
  return edges.map(edge => {
    // 根据边类型设置不同的颜色
    let color = '#aaa'; // 默认灰色
    let dashed = false;

    // 根据边类型设置颜色
    switch(edge.type) {
      case 'PRE_COURSE':
        color = '#FF9500'; // 橙色
        break;
      case 'COURSE_KNOWLEDGE':
        color = '#1890FF'; // 蓝色
        break;
      case 'PRE_KNOWLEDGE':
        color = '#52C41A'; // 绿色
        dashed = true;  // 前置知识使用虚线
        break;
      case 'CASE_COMPONENT':
        color = '#722ED1'; // 紫色
        break;
      case 'RELATED':
        color = '#F5222D'; // 红色
        dashed = true;  // 关联关系使用虚线
        break;
    }

    return {
      ...edge,
      style: {
        ...edge.style,
        stroke: color,
        lineDash: dashed ? [5, 5] : null,
      }
    };
  });
};

// 是否显示空结果提示
const showEmptyTip = ref(false);

// 搜索处理函数
const handleSearch = async () => {
  await graphStore.searchGraph();
  // 搜索后更新图形
  if (graph) {
    // 获取当前图数据
    const graphData = {
      nodes: applyNodeStyle(graphStore.graphData.nodes),
      edges: applyEdgeStyle(graphStore.graphData.edges),
    };

    // 判断搜索结果是否为空
    showEmptyTip.value = graphData.nodes.length === 0;

    // 处理平行边
    const offsetDiff = 10;
    const multiEdgeType = 'quadratic';
    const singleEdgeType = 'line';
    const loopEdgeType = 'loop';
    if (graphData.edges && graphData.edges.length > 0) {
      G6.Util.processParallelEdges(graphData.edges, offsetDiff, multiEdgeType, singleEdgeType, loopEdgeType);
    }

    // 更新图数据和视图
    graph.changeData(graphData);

    // 重新应用筛选，确保搜索结果遵循筛选规则
    if (window.graph && typeof window.graph.get === 'function') {
      setTimeout(() => {
        const event = new CustomEvent('applyGraphFilters');
        window.dispatchEvent(event);
      }, 50);
    }
  }
};

// 重置图形到初始状态
const resetGraph = async () => {
  // 清空搜索框
  searchKeyword.value = '';
  selectedType.value = '';

  // 隐藏空结果提示
  showEmptyTip.value = false;

  // 重新获取初始图数据
  await graphStore.fetchInitialGraph();

  // 更新图形
  if (graph) {
    const graphData = {
      nodes: applyNodeStyle(graphStore.graphData.nodes),
      edges: applyEdgeStyle(filterValidEdges(graphStore.graphData.edges, graphStore.graphData.nodes)),
    };

    // 处理平行边
    const offsetDiff = 10;
    const multiEdgeType = 'quadratic';
    const singleEdgeType = 'line';
    const loopEdgeType = 'loop';
    if (graphData.edges && graphData.edges.length > 0) {
      G6.Util.processParallelEdges(graphData.edges, offsetDiff, multiEdgeType, singleEdgeType, loopEdgeType);
    }

    // 更新图数据和视图
    graph.changeData(graphData);

    // 重新应用筛选，确保图形保持筛选状态
    if (window.graph && typeof window.graph.get === 'function') {
      setTimeout(() => {
        const event = new CustomEvent('applyGraphFilters');
        window.dispatchEvent(event);
      }, 50);
    }
  }
};

// 添加防抖函数
function debounce(fn: Function, delay: number) {
  let timer: NodeJS.Timeout | null = null;
  return function (...args: any[]) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

// 加载节点的一度邻居
const loadNodeNeighbors = async (nodeId: string) => {
  await graphStore.loadNodeNeighbors(nodeId);

  // 加载完成后更新图形
  if (graph) {
    // 获取当前图数据
    const graphData = {
      nodes: applyNodeStyle(graphStore.graphData.nodes),
      edges: applyEdgeStyle(filterValidEdges(graphStore.graphData.edges, graphStore.graphData.nodes)),
    };

    // 处理平行边
    const offsetDiff = 10;
    const multiEdgeType = 'quadratic';
    const singleEdgeType = 'line';
    const loopEdgeType = 'loop';
    if (graphData.edges && graphData.edges.length > 0) {
      G6.Util.processParallelEdges(graphData.edges, offsetDiff, multiEdgeType, singleEdgeType, loopEdgeType);
    }

    // 更新图数据和视图
    graph.changeData(graphData);

    // 重新应用筛选，确保新加载的节点和边也遵循筛选规则
    if (window.graph && typeof window.graph.get === 'function') {
      // 触发图例组件中的筛选应用
      // 这将间接调用KgLegend组件中的applyFilters方法
      setTimeout(() => {
        // 延迟执行，确保图形数据更新完成
        const event = new CustomEvent('applyGraphFilters');
        window.dispatchEvent(event);
      }, 50);
    }
  }
};

// 筛选有效的边（源节点和目标节点都存在于当前图中）
const filterValidEdges = (edges: any[], nodes: any[]) => {
  // 创建节点ID集合，用于快速查找
  const nodeIdSet = new Set(nodes.map(node => node.id));

  // 过滤出源节点和目标节点都存在的边
  return edges.filter(edge => {
    return nodeIdSet.has(edge.source) && nodeIdSet.has(edge.target);
  });
};

let graph: any;

// 图形实例化
onMounted(async () => {
  // 获取节点类型
  await graphStore.fetchNodeTypes();

  if (!container.value) return;

  // 确保容器有正确的初始高度
  const width = container.value.clientWidth;
  const height = container.value.clientHeight || window.innerHeight - 100;

  // 监听容器大小变化
  const resizeObserver = new ResizeObserver(() => {
    if (!container.value) return;
    const newWidth = container.value.clientWidth;
    const newHeight = container.value.clientHeight;
    graph?.changeSize(newWidth, newHeight);
    // 更新布局中心点
    if (graph?.get('layout')) {
      const layoutConfig = graph.get('layout');
      graph.updateLayout({
        ...layoutConfig,
        center: [newWidth / 2, newHeight / 2],
        width: newWidth - 100,
        height: newHeight - 100,
      });
    }
  });

  resizeObserver.observe(container.value);

  const toolbar = new G6.ToolBar({
    position: { x: 15, y: 15 },
  });
  const menu = new G6.Menu({
    getContent(evt) {
      if (evt.item) {
        const itemType = evt.item.getType();
        if (itemType === 'node') {
          return `<ul>
            <li title='explore-neighbors'>查看邻居节点</li>
          </ul>`;
        }
      }
      return '';
    },
    handleMenuClick(target: HTMLElement, item: any) {
      const action = target.getAttribute('title');

      switch (action) {
        case 'explore-neighbors':
          if (item && item.getType() === 'node') {
            const nodeModel = item.getModel();
            loadNodeNeighbors(nodeModel.id);
          }
          break;
      }
    },
    itemTypes: ['node'],
  });

  graph = new G6.Graph({
    container: container.value,
    width,
    height,
    enabledStack: true, // 开启 redo & undo
    animate: true, // Boolean，切换布局时是否使用动画过度，默认为 false
    animateCfg: {
      duration: 1000, // 增加动画时长，使过渡更平滑
      easing: 'easeInOutQuad', // 使用更平滑的缓动函数
    },
    linkCenter: false, // 边连接到节点的锚点而不是中心
    layout: {
      type: 'force',
      preventOverlap: true,
      nodeSpacing: 30, // 减小节点间距
      linkDistance: 200, // 增加边的长度
      center: [width / 2, height / 2],
      nodeStrength: -50, // 减小节点间斥力
      edgeStrength: 0.8, // 增加边的弹性
      width: width - 100,
      height: height - 100,
      // 重力
      gravity: 20, // 增加重力，使节点更向中心靠拢
      alphaDecay: 0.02, // 增加衰减速度，使布局更快稳定
      onTick: () => {
        const nodes = graph.getNodes();
        const padding = 20; // 减小边界padding
        nodes.forEach((node: any) => {
          const model = node.getModel();
          model.x = Math.max(padding, Math.min(width - padding, model.x));
          model.y = Math.max(padding, Math.min(height - padding, model.y));
        });
      },
    },
    defaultNode: {
      // size: 40, // 注释掉默认大小，使用节点自己的size属性
      style: {
        fill: '#5B8FF9',
        stroke: '#3057e3',
        lineWidth: 2,
      },
      labelCfg: {
        style: {
          fill: '#000000',
          fontSize: 14,
        },
      },
    },
    defaultEdge: {
      type: 'quadratic',
      style: {
        stroke: '#aaa',
        lineWidth: 2,
        endArrow: {
          path: G6.Arrow.triangle(8, 8, 0),
          fill: '#aaa',
        },
      },
      labelCfg: {
        style: {
          fill: '#666',
          fontSize: 12,
        },
        autoRotate: true,
      },
    },
    // 节点不同状态下的样式集合
    nodeStateStyles: {
      // 鼠标 hover 上节点，即 hover 状态为 true 时的样式
      hover: {
        fill: 'lightsteelblue',
      },
      // 鼠标点击节点，即 click 状态为 true 时的样式
      click: {
        stroke: '#000',
        lineWidth: 3,
      },
    },
    // 边不同状态下的样式集合
    edgeStateStyles: {
      // 鼠标 hover 上边，即 hover 状态为 true 时的样式
      hover: {
        stroke: '#1890ff',
        lineWidth: 3,
      },
      // 鼠标点击边，即 click 状态为 true 时的样式
      click: {
        stroke: 'steelblue',
        lineWidth: 3,
      },
    },
    modes: {
      default: [
        'drag-canvas',
        'zoom-canvas',
        // 'drag-node',
        {
          type: 'create-edge',
          key: 'alt',
          trigger: 'click',
        },
      ],
    },
    plugins: [toolbar, menu], // 配置插件
  });

  try {
    // 使用store获取初始图数据
    await graphStore.fetchInitialGraph();

    // 获取当前图数据
    const graphData = {
      nodes: applyNodeStyle(graphStore.graphData.nodes),
      edges: applyEdgeStyle(filterValidEdges(graphStore.graphData.edges, graphStore.graphData.nodes)),
    };

    // 初始时不显示空结果提示
    showEmptyTip.value = false;

    // 处理平行边
    const offsetDiff = 10;
    const multiEdgeType = 'quadratic';
    const singleEdgeType = 'line';
    const loopEdgeType = 'loop';
    if (graphData.edges && graphData.edges.length > 0) {
      G6.Util.processParallelEdges(graphData.edges, offsetDiff, multiEdgeType, singleEdgeType, loopEdgeType);
    }

    console.log('Processed Data:', graphData);

    // 初始化图数据
    graph.data(graphData);
    graph.render();

    // 将图实例挂载到window对象，方便KgLegend组件访问
    window.graph = graph;

    // 添加拖拽事件处理
    graph.on('node:dragstart', function (e) {
      graph.layout();
      refreshDragedNodePosition(e);
    });

    graph.on('node:drag', function (e) {
      refreshDragedNodePosition(e);
    });

    graph.on('node:dragend', function (e) {
      e.item.get('model').fx = null;
      e.item.get('model').fy = null;
    });

    // 鼠标进入节点
    graph.on('node:mouseenter', e => {
      const nodeItem = e.item; // 获取鼠标进入的节点元素对象
      graph.setItemState(nodeItem, 'hover', true); // 设置当前节点的 hover 状态为 true
    });

    // 鼠标离开节点
    graph.on('node:mouseleave', e => {
      const nodeItem = e.item; // 获取鼠标离开的节点元素对象
      graph.setItemState(nodeItem, 'hover', false); // 设置当前节点的 hover 状态为 false
    });

    // 鼠标进入边
    graph.on('edge:mouseenter', e => {
      const edgeItem = e.item;
      graph.setItemState(edgeItem, 'hover', true);
    });

    // 鼠标离开边
    graph.on('edge:mouseleave', e => {
      const edgeItem = e.item;
      graph.setItemState(edgeItem, 'hover', false);
    });

    // 点击节点
    graph.on('node:click', e => {
      // 先将所有当前是 click 状态的节点置为非 click 状态
      const clickNodes = graph.findAllByState('node', 'click');
      clickNodes.forEach(cn => {
        graph.setItemState(cn, 'click', false);
      });
      const nodeItem = e.item; // 获取被点击的节点元素对象
      graph.setItemState(nodeItem, 'click', true); // 设置当前节点的 click 状态为 true
    });

    // 双击节点加载邻居
    graph.on('node:dblclick', e => {
      const node = e.item;
      if (node) {
        const nodeModel = node.getModel();
        isNewNode.value = false;
        graphStore.setCurrentNode(nodeModel); // 使用store设置当前节点

        // 判断是否要加载邻居节点，或者打开节点编辑面板
        if (e.originalEvent.ctrlKey || e.originalEvent.metaKey) {
          // 按下Ctrl/Meta键双击节点，加载邻居
          loadNodeNeighbors(nodeModel.id);
        } else {
          // 普通双击，打开编辑面板
          drawerVisible.value = true;
        }
      }
    });

    // 点击边
    graph.on('edge:click', e => {
      // 先将所有当前是 click 状态的边置为非 click 状态
      const clickEdges = graph.findAllByState('edge', 'click');
      clickEdges.forEach(ce => {
        graph.setItemState(ce, 'click', false);
      });
      const edgeItem = e.item; // 获取被点击的边元素对象
      graph.setItemState(edgeItem, 'click', true); // 设置当前边的 click 状态为 true
    });

    // 窗口大小改变时自适应
    window.onresize = debounce(() => {
      console.log('Resize event');
      if (!graph || graph.get('destroyed')) return;
      if (!container.value || !container.value.clientWidth || !container.value.clientHeight) return;
      const newWidth = container.value.clientWidth;
      const newHeight = container.value.clientHeight;
      graph.changeSize(newWidth, newHeight);
      // 更新布局配置
      if (graph.get('layout')) {
        const layoutConfig = graph.get('layout');
        graph.updateLayout({
          ...layoutConfig,
          center: [newWidth / 2, newHeight / 2],
          width: newWidth - 100,
          height: newHeight - 100,
        });
      }
    }, 500); // 500ms 的延迟

  } catch (error) {
    console.error('Failed to load graph data:', error);
  }
});

function refreshDragedNodePosition(e: any) {
  const model = e.item.get('model');
  model.fx = e.x;
  model.fy = e.y;
}
</script>

<template>
  <div class="graph-container">
    <!-- 搜索框 -->
    <div class="search-box">
      <el-select v-model="selectedType" placeholder="选择节点类型" class="type-select">
        <el-option
          v-for="type in nodeTypes"
          :key="type.type"
          :label="type.name"
          :value="type.type"
        />
      </el-select>
      <el-input
        v-model="searchKeyword"
        placeholder="输入搜索关键词"
        class="keyword-input"
        @keyup.enter="handleSearch"
      >
        <template #append>
          <el-button @click="handleSearch">搜索</el-button>
        </template>
      </el-input>
      <el-button @click="resetGraph" type="primary" plain>
        <el-icon><Refresh /></el-icon>重置
      </el-button>
    </div>

    <div ref="container" id="container" />

    <!-- 空结果提示 -->
    <div v-if="showEmptyTip" class="empty-tip">
      <el-empty description="没有找到相关结果" />
      <el-button type="primary" @click="resetGraph">返回初始状态</el-button>
    </div>

    <!-- 使用新的节点详情组件 -->
    <kg-node-detail v-model:visible="drawerVisible" />

    <!-- 使用提示 - 引入拆分后的组件 -->
    <kg-tips position="bottom-right" />

    <!-- 图例组件 -->
    <kg-legend position="top-left" />
  </div>
</template>

<style scoped lang="scss">
.graph-container {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;

  #container {
    flex: 1;
    background: #fff;
  }

  .search-box {
    position: absolute;
    top: 20px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 10px;
    background: transparent;
    padding: 10px;
    z-index: 1000;

    .type-select {
      width: 150px;
    }

    .keyword-input {
      width: 300px;
    }
  }

  .empty-tip {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(255, 255, 255, 0.9);
    padding: 20px;
    border-radius: 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 15px;
    z-index: 10;
  }
}

.tips {
  display: none; /* 删除旧的样式，使用组件中的样式 */
}
</style>
